package com.et114.components.osworkflow4Ibatis;

import java.math.BigDecimal;
import java.util.*;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ibatis.sqlmap.client.SqlMapClient;
import com.opensymphony.module.propertyset.*;

/*
 * @author guanhw
 */
public class IBatisPropertySet extends AbstractPropertySet {
	protected Log log = LogFactory.getLog( this.getClass( ) );
	protected String								globalKey;
	protected SqlMapClient							sqlMapClient;
	
	public void setSqlMapClient ( SqlMapClient sqlMapClient ) {
		this.sqlMapClient = sqlMapClient;
	}
	
	public SqlMapClient getSqlMapClient ( ) {
		return sqlMapClient;
	}
	
	public Collection getKeys ( String prefix , int type )
			throws PropertyException {
		if ( prefix == null ) {
			prefix = "";
		}
		
		SqlMapClient mapper = getSqlMapClient ( );
		try {
			Map param = new HashMap ( );
			param.put ( "prefix" , prefix );
			param.put ( "globalKey" , globalKey );
			if ( type != 0 ) {
				param.put ( "itemType" , new Integer ( type ) );
			}
			List list = mapper.queryForList ( "selectProperty" , param );
			ArrayList r = new ArrayList ( );
			log.debug ( "list count: " + list.size ( ) );
			
			for ( int i = 0 ; i < list.size ( ) ; i ++ ) {
				PropertyData data = ( PropertyData ) list.get ( i );
				r.add ( data.getItemKey ( ) );
				log.debug ( "result item: " + data.getItemKey ( ) );
			}
			
			return r;
		} catch ( Exception e ) {
			throw new PropertyException ( e.getMessage ( ) );
		}
	}
	
	public int getType ( String key ) throws PropertyException {
		SqlMapClient mapper = getSqlMapClient ( );
		try {
			Map param = new HashMap ( );
			param.put ( "globalKey" , globalKey );
			param.put ( "itemKey" , key );
			PropertyData data = ( PropertyData ) mapper.queryForObject (
					"selectProperty" , param );
			log.debug ( "query type: " + data.getItemType ( ) );
			
			return data.getItemType ( );
		} catch ( Exception e ) {
			throw new PropertyException ( e.getMessage ( ) );
		}
	}
	
	public boolean exists ( String key ) throws PropertyException {
		return getType ( key ) != 0;
	}
	
	public void init ( Map config , Map args ) {
		globalKey = ( String ) args.get ( "globalKey" );
		setSqlMapClient ( ( SqlMapClient ) args.get ( "sqlMapClient" ) );
	}
	
	public void remove ( String key ) throws PropertyException {
		SqlMapClient mapper = getSqlMapClient ( );
		try {
			PropertyData data = new PropertyData ( );
			data.setGlobalKey ( globalKey );
			data.setItemKey ( key );
			
			int i = mapper.delete ( "deleteProperty" , data );
			log.debug ( "delete property key: " + data.getItemKey ( )
					+ ", affected rows: " + i );
		} catch ( Exception e ) {
			throw new PropertyException ( e.getMessage ( ) );
		}
	}
	
	protected void setImpl ( int type , String key , Object value )
			throws PropertyException {
		if ( value == null ) {
			throw new PropertyException (
					"IBatisPropertySet does not allow for null values to be stored" );
		}
		
		SqlMapClient mapper = getSqlMapClient ( );
		try {
			PropertyData data = new PropertyData ( );
			data.setGlobalKey ( globalKey );
			data.setItemKey ( key );
			data.setItemType ( type );
			setValues ( data , type , key , value );
			
			log.debug ( "execute updata: updateProperty" );
			int rows = mapper.update ( "updateProperty" , data );
			log.debug ( "affected rows: " + rows );
			
			if ( rows != 1 ) {
				// ok, this is a new value, insert it
				log.debug ( "execute insert insertProperty" );
				mapper.insert ( "insertProperty" , data );
				log.debug ( "inserted object" );
			}
		} catch ( Exception e ) {
			throw new PropertyException ( e.getMessage ( ) );
		}
	}
	
	protected Object get ( int type , String key ) throws PropertyException {
		Object o = null;
		SqlMapClient mapper = getSqlMapClient ( );
		try {
			Map param = new HashMap ( );
			param.put ( "globalKey" , globalKey );
			param.put ( "itemKey" , key );
			PropertyData data = ( PropertyData ) mapper.queryForObject (
					"selectProperty" , param );
			log.debug ( "result: " + data + ", type: " + data.getItemType ( ) );
			
			if ( data.getItemType ( ) != type ) {
				throw new InvalidPropertyTypeException ( );
			}
			
			switch ( type ) {
				case PropertySet.BOOLEAN :
					int boolVal = data.getNumberValue ( ).intValue ( );
					o = new Boolean ( boolVal == 1 );
					break;
				case PropertySet.TEXT :
					o = data.getDataValue ( );
					;
					break;
				case PropertySet.DATE :
					o = data.getDateValue ( );
					break;
				case PropertySet.DOUBLE :
					o = data.getFloatValue ( );
					break;
				case PropertySet.INT :
					o = data.getNumberValue ( );
					break;
				case PropertySet.LONG :
					o = data.getNumberValue ( );
					break;
				case PropertySet.STRING :
					o = data.getStringValue ( );
					break;
				default :
					throw new InvalidPropertyTypeException (
							"IBatisPropertySet doesn't support this type yet." );
			}
		} catch ( Exception e ) {
			throw new PropertyException ( e.getMessage ( ) );
		}
		log.debug ( "return object: " + o );
		return o;
	}
	
	private void setValues ( PropertyData data , int type , String key ,
			Object value ) throws PropertyException {
		switch ( type ) {
			case PropertySet.BOOLEAN :
				Boolean boolVal = ( Boolean ) value;
				data.setNumberValue ( boolVal.booleanValue ( ) ? BigDecimal
						.valueOf ( 1L ) : BigDecimal.valueOf ( 0L ) );
				break;
			
			case PropertySet.TEXT :
				// Data dataa = (Data)value;
				data.setDataValue ( value.toString ( ) );
				break;
			
			case PropertySet.DATE :
				Date date = ( Date ) value;
				data.setDateValue ( date );
				break;
			
			case PropertySet.DOUBLE :
				Double d = ( Double ) value;
				data.setFloatValue ( new Float ( d.floatValue ( ) ) );
				break;
			
			case PropertySet.INT :
				Integer i = ( Integer ) value;
				data.setNumberValue ( java.math.BigDecimal.valueOf ( i
						.intValue ( ) ) );
				break;
			
			case PropertySet.LONG :
				Long l = ( Long ) value;
				data.setNumberValue ( java.math.BigDecimal.valueOf ( l
						.intValue ( ) ) );
				break;
			
			case PropertySet.STRING :
				data.setStringValue ( ( String ) value );
				break;
			
			default :
				throw new PropertyException ( "This type isn't supported!" );
		}
	}

	public void remove ( ) throws PropertyException {
		// TODO Auto-generated method stub
		
	}
	
	/*
	 * private void closeConnection(Connection conn) { try { if ((conn != null)
	 * && !conn.isClosed()) { conn.commit(); } } catch (SQLException e) {
	 * log.error("Could not commit connection"); } try { if ((conn != null) &&
	 * !conn.isClosed()) { conn.close(); } } catch (SQLException e) {
	 * log.error("Could not close connection"); } }
	 */
}
